#include "xdgTcpClient.h"
#include <QDataStream>
#include <QEventLoop>
#include <QTimer>
#include <QDebug>
#include <QThread>
#include <QCoreApplication> // 用于 sendAndReceive 的 GUI 线程检查
#include <QtEndian>



xdgTcpClient::xdgTcpClient(QObject *parent)
    : QObject(parent),
    m_socket(new QTcpSocket(this)), // 1. 直接在构造函数中创建
    m_expectedBodySize(-1),
    m_isBlockingCallActive(false),
    m_blockingLoop(nullptr)
{
    // 2. 直接在构造函数中连接信号
    // 这些连接将始终在 xdgTcpClient 实例所属的线程中被处理
    connect(m_socket, &QTcpSocket::connected, this, &xdgTcpClient::onConnected);
    connect(m_socket, &QTcpSocket::disconnected, this, &xdgTcpClient::onDisconnected);
    connect(m_socket, &QTcpSocket::readyRead, this, &xdgTcpClient::onReadyRead);

    // 使用 QOverload 解决信号重载
    connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::errorOccurred),
            this, &xdgTcpClient::onErrorOccurred);
}

xdgTcpClient::~xdgTcpClient()
{
    // m_socket 是 this 的子对象，会自动被 Qt 清理
}

// =================================================================================
// 线程安全的公共 API (调度器)
// =================================================================================

void xdgTcpClient::connectToServer(const QString& host, quint16 port)
{
    // 将实际工作排队到 m_client 的线程事件循环中
    QMetaObject::invokeMethod(this, "_p_doConnect", Qt::QueuedConnection,
                              Q_ARG(QString, host),
                              Q_ARG(quint16, port));
}

void xdgTcpClient::disconnectFromServer()
{
    QMetaObject::invokeMethod(this, "_p_doDisconnect", Qt::QueuedConnection);
}

void xdgTcpClient::sendMessage(const QByteArray& message)
{
    // QByteArray 是隐式共享的，可以安全地跨线程传递
    QMetaObject::invokeMethod(this, "_p_doSend", Qt::QueuedConnection,
                              Q_ARG(QByteArray, message));
}

bool xdgTcpClient::isConnected() const
{
    // 如果在同一个线程调用，直接返回
    if (QThread::currentThread() == this->thread()) {
        return m_socket->state() == QAbstractSocket::ConnectedState;
    }

    // 跨线程调用，必须使用阻塞队列
    QAbstractSocket::SocketState state = QAbstractSocket::UnconnectedState;
    // 使用 const_cast<xdgTcpClient*>(this) 来获取一个非 const 指针
    QMetaObject::invokeMethod(const_cast<xdgTcpClient*>(this), "_p_getState", Qt::BlockingQueuedConnection,
                              Q_RETURN_ARG(QAbstractSocket::SocketState, state));

    return state == QAbstractSocket::ConnectedState;
}

// =================================================================================
// 内部工作槽 (在客户端线程中执行)
// =================================================================================

void xdgTcpClient::_p_doConnect(const QString& host, quint16 port)
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::_p_doConnect", "Must be called from the object's own thread.");
    m_socket->connectToHost(host, port);
}

void xdgTcpClient::_p_doDisconnect()
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::_p_doDisconnect", "Must be called from the object's own thread.");
    if (m_socket->state() != QAbstractSocket::UnconnectedState) {
        m_socket->disconnectFromHost();
    }
}

void xdgTcpClient::_p_doSend(const QByteArray& message)
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::_p_doSend", "Must be called from the object's own thread.");

    if (m_socket->state() != QAbstractSocket::ConnectedState) {
        qWarning("xdgTcpClient: Not connected, failed to send message.");
        return;
    }

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setByteOrder(QDataStream::LittleEndian);
    out << (qint32)message.size();
    block.append(message);

    if (m_socket->write(block) != block.size()) {
        qWarning("xdgTcpClient: Failed to write full message to socket.");
    }
}

QAbstractSocket::SocketState xdgTcpClient::_p_getState() const
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::_p_getState", "Must be called from the object's own thread.");
    return m_socket->state();
}

// =================================================================================
// Socket 信号槽 (在客户端线程中执行, 无需 QMutex)
// =================================================================================

void xdgTcpClient::onConnected()
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::onConnected", "Must be called from the object's own thread.");
    m_buffer.clear();
    m_expectedBodySize = -1;
    emit connected();
}

void xdgTcpClient::onDisconnected()
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::onDisconnected", "Must be called from the object's own thread.");
    m_buffer.clear();
    m_expectedBodySize = -1;
    emit disconnected();
}

void xdgTcpClient::onErrorOccurred(QAbstractSocket::SocketError socketError)
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::onErrorOccurred", "Must be called from the object's own thread.");
    emit errorOccurred(socketError);
}

void xdgTcpClient::onReadyRead()
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::onReadyRead", "Must be called from the object's own thread.");

    // 将所有可用数据读入缓冲区
    m_buffer.append(m_socket->readAll());

    // 处理缓冲区中的完整数据包
    processBuffer();
}

void xdgTcpClient::processBuffer()
{
    Q_ASSERT_X(QThread::currentThread() == this->thread(), "xdgTcpClient::processBuffer", "Must be called from the object's own thread.");

    while (true)
    {
        // 1. 尝试读取包头 (消息体长度)
        if (m_expectedBodySize == -1) {
            if (m_buffer.size() < 4) {
                break; // 缓冲区中没有足够的字节来构成一个包头
            }
            QDataStream stream(m_buffer.left(4));
            stream.setByteOrder(QDataStream::LittleEndian);
            stream >> m_expectedBodySize;
            m_buffer.remove(0, 4);
        }

        // 2. 检查包体大小是否有效
        if (m_expectedBodySize < 0) {
            qWarning("xdgTcpClient: Invalid message body size %d. Resetting buffer.", m_expectedBodySize);
            m_buffer.clear();
            m_expectedBodySize = -1;
            // 协议错误，主动断开
            _p_doDisconnect();
            break;
        }

        // 3. 尝试读取包体
        if (m_buffer.size() < m_expectedBodySize) {
            break; // 缓冲区中没有足够的字节来构成一个完整的包体
        }

        // 4. 提取完整的消息
        QByteArray messageBody = m_buffer.left(m_expectedBodySize);
        m_buffer.remove(0, m_expectedBodySize);
        m_expectedBodySize = -1; // 重置，准备接收下一个包

        // 5. 决定如何分发消息 (同步调用 或 异步信号)
        bool handledByBlockingCall = false;
        {
            QMutexLocker locker(&m_blockingMutex);
            if (m_isBlockingCallActive) {
                m_blockingResponse = messageBody;
                if (m_blockingLoop) m_blockingLoop->quit(); // 唤醒 sendAndReceive
                m_isBlockingCallActive = false; // 标记已处理
                handledByBlockingCall = true;
            }
        } // 释放锁

        if (!handledByBlockingCall) {
            // 没有活动的阻塞调用，作为常规异步消息发出
            emit messageReceived(messageBody);
        }

        // 继续循环，处理缓冲区中的下一个包 (粘包)
    }
}

// =================================================================================
// 阻塞调用 (在 *调用者* 线程中执行, e.g. 非GUI的工作线程)
// =================================================================================

QByteArray xdgTcpClient::sendAndReceive(const QByteArray& request, int timeoutMsecs)
{
    // 警告：此函数不能在 GUI 线程或 xdgTcpClient 自己的线程中调用
    if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
        qWarning("xdgTcpClient::sendAndReceive: FATAL - Cannot call blocking function from GUI thread.");
        return QByteArray();
    }
    if (QThread::currentThread() == this->thread()) {
        qWarning("xdgTcpClient::sendAndReceive: FATAL - Cannot call blocking function from client's own thread (deadlock).");
        return QByteArray();
    }

    QEventLoop loop;
    QTimer timer;
    timer.setSingleShot(true);

    // 连接超时
    connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    // 连接断开 (也应终止等待)
    auto discConn = connect(this, &xdgTcpClient::disconnected, &loop, &QEventLoop::quit);

    QByteArray response;

    { // --- 关键区域开始 ---
        QMutexLocker locker(&m_blockingMutex);
        if (m_isBlockingCallActive) {
            qWarning("xdgTcpClient::sendAndReceive: Another blocking call is already in progress.");
            disconnect(discConn);
            return QByteArray();
        }
        m_isBlockingCallActive = true;
        m_blockingResponse.clear();
        m_blockingLoop = &loop;
    } // --- 关键区域结束 ---

    timer.start(timeoutMsecs);

    // 异步派发“发送”命令
    sendMessage(request);

    // 阻塞调用者线程，等待 processBuffer 唤醒 loop 或超时
    loop.exec();

    { // --- 关键区域开始 ---
        QMutexLocker locker(&m_blockingMutex);
        if (timer.isActive()) { // 是被 m_blockingLoop->quit() 唤醒的 (非超时)
            timer.stop();
            response = m_blockingResponse;
        } else { // 是被 QTimer 唤醒的 (超时)
            qWarning("xdgTcpClient::sendAndReceive: Operation timed out.");
            // response 已经是空的
        }

        // 清理状态
        m_isBlockingCallActive = false;
        m_blockingLoop = nullptr;
        m_blockingResponse.clear();
    } // --- 关键区域结束 ---

    disconnect(discConn);
    return response;
}
